package com.jdy.haoduoaiteacher.socket;

import android.content.Context;

import com.jdy.haoduoaiteacher.MyTeacherApp;
import com.jdy.haoduoaiteacher.util.LeConfig;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

public class TCPClient {
  private Selector selector;

  SocketChannel socketChannel;

  private String hostIp;

  private int hostListenningPort;

  private static TCPClient s_Tcp = null;

  public boolean isInitialized = false;
  int a = 1;
  int b = 2;
  // String heart = (char) a + "{\"data\": \"" + LeConfig.MAC_ID
  // + "\", \"code\": 110}" + (char) b;
  private static Context context;

  public static synchronized TCPClient instance() {
    if (s_Tcp == null) {

      s_Tcp = new TCPClient(LeConfig.g_ServerIP, LeConfig.FILE_PORT);
      context = MyTeacherApp.getAppContext();
    }
    return s_Tcp;
  }

  /**
   * 构�?函数
   * 
   * @param HostIp
   * @param HostListenningPort
   * @throws IOException
   */
  public TCPClient(String HostIp, int HostListenningPort) {
    this.hostIp = LeConfig.g_ServerIP;
    this.hostListenningPort = LeConfig.FILE_PORT;

    try {
      initialize();
      this.isInitialized = true;
    } catch (IOException e) {
      this.isInitialized = false;
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (Exception e) {
      this.isInitialized = false;
      e.printStackTrace();
    }
  }

//  public static int PREFIX = 1;
  public static int SUFFIX = 0;

  private String fabricateCommand(JSONObject content, int codeValue) {
    JSONObject rawCommand = new JSONObject();
    try {
      rawCommand.put("data", content);
      rawCommand.put("code", codeValue);
    } catch (JSONException e) {

      e.printStackTrace();
    }
    String commandString =  rawCommand.toString()
        + (char) SUFFIX;
    return commandString;
  }

  public void initialize() throws IOException {
    boolean done = false;

    try {
      System.out.println("=====xxb====hostIp=====" + hostIp + ";;;port=="
          + hostListenningPort);
      socketChannel = SocketChannel.open(new InetSocketAddress(hostIp,
          hostListenningPort));
      if (socketChannel != null) {
        socketChannel.socket().setTcpNoDelay(false);
        socketChannel.socket().setKeepAlive(true);
        socketChannel.socket().setSoTimeout(Const.SOCKET_READ_TIMOUT);
        socketChannel.configureBlocking(false);

        selector = Selector.open();
        if (selector != null) {
          socketChannel.register(selector, SelectionKey.OP_READ);
          done = true;
        }
        JSONObject data = new JSONObject();
        try {
          // data.put("macid", LeConfig.MAC_ID);
          // PyCmd cmd = new PyCmd(PyCmd.CODE_FOR_PY, data);
          // For test
          data.put("macid", LeConfig.MAC_ID);
          data.put("uid", LeConfig.PHONE_NUM);
          String cmd = fabricateCommand(data, 200);
          sendMsg(cmd.toString());
        } catch (JSONException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    } catch (SocketTimeoutException e) {
      e.printStackTrace();
    } catch (ConnectException e2) {
      e2.printStackTrace();
    } finally {
      if (!done && selector != null) {
        selector.close();
      }
      if (!done) {
        if (socketChannel != null)
          socketChannel.close();
      }
    }
  }

  static void blockUntil(SelectionKey key, long timeout) throws IOException {

    int nkeys = 0;
    if (timeout > 0) {
      nkeys = key.selector().select(timeout);

    } else if (timeout == 0) {
      nkeys = key.selector().selectNow();
    }

    if (nkeys == 0) {
      throw new SocketTimeoutException();
    }
  }

  public void sendMsg(String message) throws IOException {
    System.out.println("=====xxb==sendmsg=====" + message);
    // --------------------------------
    // Intent tt = new Intent("com.xiaoxiaoban.log");
    // tt.putExtra("data","=====send====="+message);
    // context.sendBroadcast(tt);
    // ------------------------
    ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes("utf-8"));

    if (socketChannel == null) {
      throw new IOException();
    }

    try {
      socketChannel.write(writeBuffer);
    } catch (ClosedChannelException e) {
      e.printStackTrace();
    }

  }

  public void sendMsg(byte[] bytes) throws IOException {
    ByteBuffer writeBuffer = ByteBuffer.wrap(bytes);

    if (socketChannel == null) {
      throw new IOException();
    }
    socketChannel.write(writeBuffer);
  }

  public synchronized Selector getSelector() {
    return this.selector;
  }

  public boolean isConnect() {
    boolean isConnect = false;
    if (this.isInitialized && this.socketChannel != null) {
      isConnect = this.socketChannel.isConnected();
    }
    return isConnect;
  }

  public void disconnectOldConnectNew() {
    closeTCPSocket();

    this.hostIp = LeConfig.g_ServerIP;
    this.hostListenningPort = LeConfig.FILE_PORT;

    try {
      initialize();
      isInitialized = true;
    } catch (IOException e) {
      isInitialized = false;
      e.printStackTrace();
    } catch (Exception e) {
      isInitialized = false;
      e.printStackTrace();
    }

    // mIp = LeConfig.g_ServerIP;
    // mPort = LeConfig.FILE_PORT;
    //
    // mHandler.removeMessages(CONNECT_SOCKET);
    // mHandler.sendEmptyMessage(CONNECT_SOCKET);
  }

  public boolean reConnect() {
    closeTCPSocket();

    try {
      initialize();
      isInitialized = true;
    } catch (IOException e) {
      isInitialized = false;
      e.printStackTrace();
    } catch (Exception e) {
      isInitialized = false;
      e.printStackTrace();
    }
    return isInitialized;
  }

  public boolean canConnectToServer() {
    try {
      if (socketChannel != null) {
        // socketChannel.socket().sendUrgentData(0xff);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("uid", String.valueOf(LeConfig.PHONE_NUM));
        String heart =  "{\"data\": {\"uid\":\""
            + LeConfig.PHONE_NUM + "\"}, \"code\": 210}" + (char) SUFFIX;

        sendMsg(heart);
      }
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      return false;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  public void closeTCPSocket() {
    try {
      if (socketChannel != null) {
        socketChannel.close();
      }

    } catch (IOException e) {

    }
    try {
      if (selector != null) {
        selector.close();
      }
    } catch (IOException e) {
    }
  }

  public synchronized void repareRead() {
    if (socketChannel != null) {
      try {
        selector = Selector.open();
        socketChannel.register(selector, SelectionKey.OP_READ);
      } catch (ClosedChannelException e) {
        e.printStackTrace();

      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}
